﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Graphics;

namespace SourFruit.level.obj
{
    public enum MovingOptions { still, upDown, leftRight, rightTriangleDown, rightTriangleUp }
    /// <summary>
    /// Base class for all the different level object, like platforms and collectables
    /// </summary>        
    public abstract class LevelObject
    {              
        private const int MOVE_UP = -1;
        private const int MOVE_DOWN = 1;
        private const int MOVE_LEFT = -1;
        private const int MOVE_RIGHT = 1;
        private Vector2 mDirection = Vector2.Zero;
        private Vector2 velocity = Vector2.Zero;
        private int posX, posY, width, height, id, imageIntervalMs, imageTimer, moveIntervalMs, moveTimer;
        private float speed;
        private Texture2D[] textureStrip;
        private Texture2D currentTexture;
        /// <summary>
        /// Determines if the object moves on it's own.
        /// </summary>
        private MovingOptions moves;

        /// <summary>  
        /// Handles the informing the receivers that the players position has changed.  
        /// </summary>  
        /// <param name="sender">The sender of the event.</param>  
        /// <param name="e">The EventArgs of the event.</param>  
        public delegate void PositionHandler(object sender, int x, int y, int id, Texture2D texture);
        public event PositionHandler PositionChanged;

        /// <summary>  
        /// Handles the informing the receivers that the players position has changed.  
        /// </summary>  
        /// <param name="sender">The sender of the event.</param>  
        /// <param name="e">The EventArgs of the event.</param>  
        public delegate void UpdateImage(int id, Texture2D texture);
        public event UpdateImage UpdateImageEvent;

        /// <summary>  
        /// Handles the informing the receivers that the players position has changed.  
        /// </summary>  
        /// <param name="sender">The sender of the event.</param>  
        /// <param name="e">The EventArgs of the event.</param>  
        public delegate void Remove(object sender, int id);
        public event Remove RemoveObject;

        /// <summary>
        /// 
        /// </summary>
        public LevelObject(int _posX, int _posY, int _width, int _height, Texture2D _texture)
        {
            this.posX = _posX;
            this.posY = _posY;
            this.width = _width;
            this.height = _height;
            this.textureStrip = null;
            this.currentTexture = _texture;
            this.moves = MovingOptions.still;
        }


        /// <summary>
        /// 
        /// </summary>
        public LevelObject(int _posX, int _posY, int _width, int _height, Texture2D[] _textureStrip, int _imageIntervalMs)
        {
            this.posX = _posX;
            this.posY = _posY;
            this.width = _width;
            this.height = _height;
            this.textureStrip = _textureStrip;
            this.currentTexture = this.textureStrip[0];
            this.imageIntervalMs = _imageIntervalMs;
            this.imageTimer = 0;
            this.moves = MovingOptions.still;
        }

        /// <summary>
        /// 
        /// </summary>
        public LevelObject(int _posX, int _posY, int _width, int _height, Texture2D _texture, MovingOptions _moves, float _speed)
        {
            this.posX = _posX;
            this.posY = _posY;
            this.width = _width;
            this.height = _height;
            this.textureStrip = null;
            this.currentTexture = _texture;
            this.moves = _moves;
            this.speed = _speed;
            this.moveIntervalMs = 1000;
            this.moveTimer = 0;
            setStartDirection();
        }


        /// <summary>
        /// 
        /// </summary>
        public LevelObject(int _posX, int _posY, int _width, int _height, Texture2D[] _textureStrip, int _imageIntervalMs, MovingOptions _moves, float _speed)
        {
            this.posX = _posX;
            this.posY = _posY;
            this.width = _width;
            this.height = _height;
            this.textureStrip = _textureStrip;
            this.currentTexture = this.textureStrip[0];
            this.imageIntervalMs = _imageIntervalMs;
            this.imageTimer = 0;
            this.moves = _moves;
            this.speed = _speed;
            setStartDirection();
        }

        public int PosX { get { return posX; } set { posX = value; } }

        public int PosY { get { return posY; } set { posY = value; } }

        public int Width { get { return width; } set { width = value; } }

        public int Height { get { return height; } set { height = value; } }

        public int ID { get { return id; } set { id = value; } }

        public Texture2D Texture { get { return currentTexture; } set { currentTexture = value;} }

        public Rectangle BoundingBox
        {
            get
            {
                return new Rectangle(
                    posX,
                    posY,
                    width,
                    height);
            }
        }

        private void setStartDirection()
        {
            switch (moves)
            {
                case MovingOptions.upDown:
                    mDirection.Y = MOVE_UP;
                    break;
                    
                case MovingOptions.leftRight:
                    mDirection.X = MOVE_LEFT;
                    break;
            }
        }

        public void CreateEventPositionChanged()
        {
            if (PositionChanged != null)
            {
               PositionChanged(this, posX, posY, id, currentTexture);
            }
        }

        public void CreateEventUpdateImage(GameTime gt)
        {
            if (UpdateImageEvent != null && textureStrip != null)
            {
                if (imageTimer > imageIntervalMs)
                {
                    Animate();
                    UpdateImageEvent(id, currentTexture);
                    imageTimer = 0;
                }
                else imageTimer += gt.ElapsedGameTime.Milliseconds;
            }
        }

        private void Animate()
        {
            for (int i = 0; i < textureStrip.Length-1; i++)
            {
                if (currentTexture.Equals(textureStrip[i])){
                    currentTexture = textureStrip[i + 1];
                    return;
                }
            }
            currentTexture = textureStrip[0];
        }

        public void MoveObject(GameTime gt)
        {
            if (moves == MovingOptions.still) return;
            switch (moves)
            {
                case MovingOptions.leftRight:
                    if (moveTimer > moveIntervalMs)
                    {
                        ChangeDirection(true);
                        moveTimer = 0;
                    }
                    else moveTimer += gt.ElapsedGameTime.Milliseconds;
                    posX += (int)(mDirection.X * speed);
                    CreateEventPositionChanged();
                    break;
                
                case MovingOptions.upDown:
                    if (moveTimer > moveIntervalMs)
                    {
                        ChangeDirection(false);
                        moveTimer = 0;
                    }
                    else moveTimer += gt.ElapsedGameTime.Milliseconds;
                    posY += (int)(mDirection.Y * speed);
                    CreateEventPositionChanged();
                    break;
            }
        }

        private void ChangeDirection(Boolean X)
        {
            if (X)
            {
                if (mDirection.X > 0) mDirection.X = MOVE_LEFT;
                else mDirection.X = MOVE_RIGHT;
            }
            else 
            {
                if (mDirection.Y > 0) mDirection.Y = MOVE_UP;
                else mDirection.Y = MOVE_DOWN;
            }
        }

        public void CreateEventRemove()
        {
            if (RemoveObject != null)
                RemoveObject(this, id);
        }
    }
}
